#include "Subsystems/SubsystemPlayers.h"
#include "Engine/Vector3.hpp"

#include "Network/Packages/MessagePackage.h"
#include "Network/Packages/EntityPackage.h"
#include "Network/PackageManager.h"

#include "Managers/GameManager.h"
#include "Managers/EntityManager.h"
#include "Managers/ComponentsManager.h"

#include "Player/PlayerData.h"

#include <fstream>

#include "Log.h"
#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"


using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    /**
     * @brief 给玩家设置 PlayerData 的 ID， 该 id 再发包同步玩家的使用时做排序用
     * @param playerData 
    */
    void SubsystemPlayers::playerDataSetID(PlayerDataPtr &playerData)
    {
        std::lock_guard<SpinLock> lk(m_playerDataMapLock);
        for(int32_t index = 0; index < UINT16_MAX; index++)
        {
            auto it = m_playerDataMap.find(index);
            if(it == m_playerDataMap.end())
            {
                playerData->playerDataID = index;
                m_playerDataMap[index] = playerData;
                Log::Info(fmt::format("给玩家 {} 赋值id: {}", playerData->username, index));
                return;
            }
        }
    }

    /**
     * @brief 回收 PlayerData 的 ID
     * @param playerData 
    */
    void SubsystemPlayers::playerDataRecycleID(PlayerDataPtr &playerData)
    {
        std::lock_guard<SpinLock> lk(m_playerDataMapLock);
        auto it = m_playerDataMap.find(playerData->playerDataID);
        if (it != m_playerDataMap.end())
        {
            m_playerDataMap.erase(it);
            Log::Info(fmt::format("回收玩家 {} 的PlayerDataID: {}", playerData->username, playerData->playerDataID));
        }
    }

    void SubsystemPlayers::addPlayer(PlayerDataPtr &playerData)
    {
        m_addPlayerQueue.enqueue(playerData);
    }

    void SubsystemPlayers::removePlayer(PlayerDataPtr &playerData)
    {
        m_removePlayerQueue.enqueue(playerData);
    }

    void SubsystemPlayers::savePlayer(PlayerDataPtr &playerData)
    {
        nlohmann::json playerJson;
        playerJson["PlayerData"] = {};
        playerJson["Components"] = {};
        playerData->save(playerJson["PlayerData"]);
        GameSingleton::componentsManager->saveComponents(playerData->entity, playerJson["Components"]);
        std::string playerFile = fmt::format("{}/{}.json", GameSingleton::gameManager->getNowWorldPlayersPath(),playerData->playerGuid.toString());
        if(Utils::SaveTextFile(playerFile, playerJson.dump()) == false)
        {
            throw std::runtime_error(fmt::format("保存玩家 {} 的数据失败，文件: {}", playerData->username, playerFile));
        }
        Log::Info(fmt::format("save player : {}", playerData->playerGuid.toString()));
    }


    void SubsystemPlayers::getAllPlayerData(std::vector<PlayerDataPtr> &playerDataVec)
    {
        std::lock_guard<SpinLock> lk(m_playerDataMapLock);
        for(auto it = m_playerDataMap.begin(); it != m_playerDataMap.end(); ++it)
        {
            playerDataVec.push_back(it->second);
        }
    }

    void SubsystemPlayers::getPlayerDataByName(const std::string &username, std::vector<PlayerDataPtr> &playerVec)
    {
        std::lock_guard<SpinLock> lk(m_playerDataMapLock);
        for(auto &pair : m_playerDataMap)
        {
            if(pair.second->username == username)
            {
                playerVec.push_back(pair.second);
            }
        }
    }

    PlayerDataPtr SubsystemPlayers::getPlayerDataByGuid(const GameGuid &guid)
    {
        std::lock_guard<SpinLock> lk(m_playerDataMapLock);
        for(auto &pair : m_playerDataMap)
        {
            if(pair.second->playerGuid == guid)
            {
                return pair.second;
            }
        }
        return nullptr;
    }

    bool SubsystemPlayers::playerGuidGetName(const GameGuid &guid, std::string& outName)
    {
        std::lock_guard<SpinLock> lk(m_playerGuidNameMapLock);
        auto it = m_playerGuidNameMap.find(guid);
        if (it != m_playerGuidNameMap.end())
        {
            outName = it->second;
            return true;
        }
        return false;
    }


    void SubsystemPlayers::onEntityAdded(entt::entity entity)
    {
    }

    void SubsystemPlayers::onEntityRemoved(entt::entity entity)
    {
    }

    void SubsystemPlayers::update(float dt)
    {
        for(auto it = m_playerDataMap.begin(); it != m_playerDataMap.end(); ++it)
        {
            if(it->second != nullptr)
            {
                it->second->update(dt);
            }
        }

        PlayerDataPtr playerData = nullptr;
        while(m_addPlayerQueue.try_dequeue(playerData))
        {
            std::string entityName = (playerData->playerClass == PlayerClass::Male) ? "MalePlayer" : "FemalePlayer";
            nlohmann::json essentialJson;
            if(GameSingleton::entityManager->tryGetEntityEssentialData(entityName, essentialJson))
            {
                Log::Info(fmt::format("加载 {} 玩家, 玩家类型: {}", playerData->playerGuid.toString(), entityName));
                // 玩家的本地数据文件
                std::string playerFile = fmt::format("{}/{}.json", GameSingleton::gameManager->getNowWorldPlayersPath(),playerData->playerGuid.toString());
                std::string playerJsonText;
                if(Utils::LoadTextFile(playerFile, playerJsonText))
                {
                    nlohmann::json playerJson = nlohmann::json::parse(playerJsonText);
                    // 合并数据
                    essentialJson["Components"].merge_patch(playerJson["Components"]);
                }
            }
            else
            {
                throw std::runtime_error(fmt::format("EntityManager 没有找到 {} 实体的基础数据，无法加载玩家", entityName));
            }
            entt::entity entity = GameSingleton::entityManager->createNewEntity();
            playerData->entity = entity;

            GameSingleton::gameRegistry->emplace<PlayerData *>(entity, playerData.get());
            GameSingleton::componentsManager->entityAddComponents(entity, essentialJson);

            // 设置 PlayerData 的 ID
            playerDataSetID(playerData);

            // 通知所有子系统，有新的实体添加
            for (auto &pair : GameSingleton::gameManager->subsystemMap)
            {
                pair.second->onEntityAdded(entity);
            }
            
            // 新添加的玩家实体要告知所有客户端
            std::shared_ptr<EntityPackage> package = std::make_shared<EntityPackage>(playerData->entity, EntityPackageType::LoadOne);
            // 非新建的话，对应的客户端已经加载了该实体，需要跳过处理
            if(playerData->isNewCreate == false)
            {
                package->sendType = PackageSendType::EXCEPT;
                package->client = playerData->client;
            }
            GameSingleton::packageManager->addSendPackageToQueue(package);


            // 消息发送，提示该玩家加入了服务器
            std::string playerAddMessage = fmt::format("玩家 {} 加入游戏", playerData->username);
            Log::Info(playerAddMessage);
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<MessagePackage>(playerAddMessage));

            m_playerGuidNameMapLock.lock();
            m_playerGuidNameMap[playerData->playerGuid] = playerData->username;
            m_playerGuidNameMapLock.unlock();
        }

        while(m_removePlayerQueue.try_dequeue(playerData))
        {
            playerDataRecycleID(playerData);
            savePlayer(playerData);

            // 通知所有子系统，有实体准备移除
            for (auto &pair : GameSingleton::gameManager->subsystemMap)
            {
                pair.second->onEntityRemoved(playerData->entity);
            }
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<EntityPackage>(playerData->entity, EntityPackageType::Remove));
            
            // 消息发送，提示该玩家退出了服务器
            std::string playerRemoveMessage = fmt::format("玩家 {} 退出游戏", playerData->username);
            Log::Info(playerRemoveMessage);
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<MessagePackage>(playerRemoveMessage));

            GameSingleton::entityManager->destoryEntity(playerData->entity);
        }
    }


    // 创建玩家群组
    bool SubsystemPlayers::createGroup(PlayerDataPtr &playerDataPtr, const std::string &groupName)
    {
        std::lock_guard<std::recursive_mutex> lk(m_groupMutex);
        if(playerDataPtr->groupKey == GameGuid::GetZeroGuid())
        {
            auto it = m_playerGroups.find(playerDataPtr->playerGuid);
            if(it != m_playerGroups.end())
            {
                playerDataPtr->groupKey = playerDataPtr->playerGuid;
                it->second.groupName = groupName;
                return true;
            }
            playerDataPtr->groupKey = playerDataPtr->playerGuid;
            
            m_playerGroups[playerDataPtr->playerGuid] = PlayerGroup();
            PlayerGroup &playerGroup = m_playerGroups[playerDataPtr->playerGuid];
            playerGroup.groupName = groupName;
            playerGroup.playerList.push_front(playerDataPtr->playerGuid);
            return true;
        }
        return false;
    }

    // 退出群组
    bool SubsystemPlayers::exitGroup(PlayerDataPtr &playerDataPtr)
    {
        std::lock_guard<std::recursive_mutex> lk(m_groupMutex);

        // 这里要使用到副本，不然在下面的循环替换中可能会出错
        const GameGuid removeGroupKey = playerDataPtr->groupKey;

        if(removeGroupKey != GameGuid::GetZeroGuid())
        {
            auto it = m_playerGroups.find(removeGroupKey);
            if(it != m_playerGroups.end())
            {
                // 如果是队伍的创建者，那么将会解散队伍
                if(playerDataPtr->playerGuid == removeGroupKey)
                {
                    m_playerDataMapLock.lock();
                    // 循环移除成员的队伍数据，注意：这里也包含船队伍创建者
                    for(auto &pair : m_playerDataMap)
                    {
                        if(pair.second != nullptr && pair.second->groupKey == removeGroupKey)
                        {
                            pair.second->groupKey = GameGuid::GetZeroGuid();
                        }
                    }
                    m_playerDataMapLock.unlock();

                    // 移除整个队伍的数据
                    m_playerGroups.erase(it);
                }
                else
                {
                    it->second.playerList.remove(removeGroupKey);
                }
            }
            playerDataPtr->groupKey = GameGuid::GetZeroGuid();
            return true;
        }
        return false;
    }

    // 加入群组
    bool SubsystemPlayers::joinGroup(PlayerDataPtr &playerDataPtr, const GameGuid& groupKey)
    {
        std::lock_guard<std::recursive_mutex> lk(m_groupMutex);
        // if(playerData->groupKey == GameGuid::GetZeroGuid())
        {
            auto it = m_playerGroups.find(groupKey);
            if(it != m_playerGroups.end())
            {
                playerDataPtr->groupKey = groupKey;
                it->second.playerList.push_front(playerDataPtr->playerGuid);
                return true;
            }
        }
        return false;
    }

    bool SubsystemPlayers::haveGroup(const GameGuid& groupKey)
    {
        std::lock_guard<std::recursive_mutex> lk(m_groupMutex);
        if(m_playerGroups.find(groupKey) != m_playerGroups.end())
        {
            return true;
        }
        return false;
    }

    void SubsystemPlayers::load(const nlohmann::json &json)
    {
        auto jsonIt = json.find("PlayerGroups_v1");
        if(jsonIt != json.end())
        {
            for(const nlohmann::json &groupJson : *jsonIt)
            {
                GameGuid groupKey = groupJson[0].get<GameGuid>();
                m_playerGroups[groupKey] = PlayerGroup();

                PlayerGroup &playerGroup = m_playerGroups[groupKey];
                playerGroup.groupName = groupJson[1].get<std::string>();
                playerGroup.playerList = groupJson[2].get<std::list<GameGuid>>();
            }
        }
        jsonIt = json.find("playerGuidMap");
        if(jsonIt != json.end())
        {
            m_playerGuidNameMap = json["playerGuidMap"].get<std::map<GameGuid, std::string>>();
        }
    }

    void SubsystemPlayers::save(nlohmann::json &json)
    {
        for(auto &pair : m_playerDataMap)
        {
            GameSingleton::gameSaveThreadPool->push_task(&SubsystemPlayers::savePlayer, this, pair.second); // savePlayer(pair.second);
        }

        std::lock_guard<std::recursive_mutex> lk(m_groupMutex);
        nlohmann::json serverGroupsJson = nlohmann::json::array();
        for(auto &pair : m_playerGroups)
        {
            nlohmann::json groupJson;
            groupJson[0] = pair.first;
            groupJson[1] = pair.second.groupName;
            groupJson[2] = pair.second.playerList;
            serverGroupsJson.push_back(groupJson);
        }
        json["PlayerGroups_v1"] = serverGroupsJson;
        json["playerGuidMap"] = m_playerGuidNameMap;
    }




    void SubsystemPlayers::saveToMsgJson(nlohmann::json &jsonData)
    {
        nlohmann::json serverGroupsJson;
        for(auto &pair : m_playerGroups)
        {
            nlohmann::json groupJson;

            MSG_VALUE_SET(groupJson, "Name", "string", pair.second.groupName);

            groupJson["Members"] = nlohmann::json::object();
            nlohmann::json &members = groupJson["Members"];

            int32_t num = 0;
            for(const GameGuid& gameGuid : pair.second.playerList)
            {
                MSG_VALUE_SET(members, std::to_string(num), "System.Guid", gameGuid.toString());
                ++num;
            }

            serverGroupsJson[pair.first.toString()] = groupJson;
        }
        jsonData["ServerGroups"] = serverGroupsJson;
    }

    static const std::string subsystemName = "Players";
    const std::string& SubsystemPlayers::getName() const
    {
        return subsystemName;
    }
    SubUpdateType SubsystemPlayers::getUpdateType()
    {
        return SubUpdateType::MainSingleUpdate;
    }
}